<?php

namespace yifang\initializer;

use yifang\App;
use Throwable;
use yifang\exception\Handle;
use yifang\exception\ErrorException;

/**
 * 错误和异常处理
 */
class Error
{
    /** @var App */
    protected $app;

    protected $initialized=false;

    /**
     * 注册异常处理
     */
    public function init(App $app)
    {
        $this->app = $app;
        $this->initialize();
    }

    /**
     * 初始化错误信息
     */
    public function initialize(){
        if(!$this->initialized){
            $this->initialized=true;
            $error_report=config("log.error_reporting",null);
            if(!isset($error_report)){
                $error_report=E_ALL;
            }
            error_reporting($error_report);
            set_error_handler(array(&$this,"appError"));
            set_exception_handler(array(&$this,"appException"));
            register_shutdown_function([$this, 'appShutdown']);
        }
    }

    /**
     * 确定错误类型是否致命
     */
    protected function isFatal($type)
    {
        return in_array($type, [E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR, E_PARSE]);
    }

    /**
     * 获取异常处理程序的实例。
     */
    protected function getExceptionHandler()
    {
        return $this->app->make(Handle::class);
    }

    /**
     * 异常处理程序
     */
    public function appException(Throwable $e)
    {
        $handler = $this->getExceptionHandler();
        $handler->report($e);
        if ($this->app->runningInConsole()) {
            //控制台错误打印

        } else {
            $handler->render($this->app->request, $e)->send();
        }
    }

    /**
     * 错误处理程序
     */
    public function appError($errno,$errstr,$errfile = '',$errline = 0)
    {
        $exception = new ErrorException($errno, $errstr, $errfile, $errline);
        if (error_reporting() & $errno) {
            throw $exception;
        }
    }

    /**
     * 关机处理程序
     */
    public function appShutdown()
    {
        if (!is_null($error = error_get_last()) && $this->isFatal($error['type'])) {
            $exception = new ErrorException($error['type'], $error['message'], $error['file'], $error['line']);
            $this->appException($exception);
        }
    }
}
